package model

import (
	myConfig "common/config"
	"common/helper"
	myUserHelp "common/userHelp"
	"database/sql"
	"errors"
	"fmt"
	g "github.com/doug-martin/goqu/v9"
	"time"
)

type TblMemberBankcard struct {
	Id         string `json:"id" db:"id" cbor:"id"`
	Uid        string `json:"uid" db:"uid" cbor:"uid"`
	Username   string `json:"username" db:"username" cbor:"username"`
	CreatedAt  int    `json:"created_at" db:"created_at" cbor:"created_at"`
	State      int    `json:"state" db:"state" cbor:"state"` //0 其他,1 默认卡
	PixAccount string `json:"pix_account" db:"pix_account" cbor:"pix_account"`
	Flag       int    `json:"flag" db:"flag" cbor:"flag"` //1 cpf 2 phone 3 email 4 CNPJ
	RealName   string `json:"real_name" db:"real_name" cbor:"real_name"`
	PixId      string `json:"pix_id" db:"pix_id" cbor:"pix_id"`
}

type memberBankData struct {
	T         int                 `json:"t"`          //列表数量
	D         []TblMemberBankcard `json:"d"`          //卡信息
	CardLimit int                 `json:"card_limit"` //绑卡数量限制
}

type TblBanktype struct {
	Id       int    `json:"id" db:"id" cbor:"id"`
	Bankname string `json:"bankname" db:"bankname" cbor:"bankname"`
	Bankcode string `json:"bankcode" db:"bankcode" cbor:"bankcode"`
	State    int    `json:"state" db:"state" cbor:"state"`
}

type bankTypeData struct {
	T int           `cbor:"t"`
	D []TblBanktype `cbor:"d"`
}

func BankcardInsert(uid, username, realName, flag, pixAccount, pixId, bankCode string) error {

	myUserHelp.LoadUserToRedis(uid)
	// 会员银行卡插入加锁
	lKey := fmt.Sprintf("bc:%s", username)
	err := Lock(lKey)

	if err != nil {
		helper.InfoLog("insert err:%s", err.Error())
		return err
	}
	defer Unlock(lKey)

	//同一个人不能设置相同的
	var data TblMemberBankcard
	que, _, _ := dialect.From("tbl_member_bankcard").Select(colsBankcard...).Where(g.Ex{"uid": uid, "pix_account": pixAccount}).Limit(1).ToSQL()
	err = meta.MerchantDB.Get(&data, que)
	if err != nil && err != sql.ErrNoRows {
		return pushLog(fmt.Errorf("%s,[%s]", err.Error(), que), helper.DBErr)
	}
	if data.Id != "" {
		helper.SqlSelectErrLog("DuplicateCardError,uid:%s,pix_id:%s,flag:%s", uid, pixId, flag)
		if flag == "1" {
			return errors.New(helper.DuplicateCardError)
		}
		if flag == "2" || flag == "3" {
			return errors.New(helper.DuplicatePhoneOrEmailError)
		}
		if flag == "4" {
			return errors.New(helper.DuplicateCNPJError)
		}
	}

	var count int
	query1, _, _ := dialect.From("tbl_member_bankcard").Select(g.COUNT(1)).Where(g.Ex{"uid": uid}).ToSQL()
	err = meta.MerchantDB.Get(&count, query1)
	if err != nil {
		return pushLog(fmt.Errorf("%s,[%s]", err.Error(), query1), helper.DBErr)
	}
	if count >= myConfig.GetGameCfgInt(myConfig.CfgCardBindLimit) {
		return errors.New(helper.BindCardLimitExceed)
	}

	bankType, err := bankNameByCode(bankCode)
	if err != nil {
		return errors.New(helper.BankNameOrCodeErr)
	}

	var state int
	if count == 0 {
		state = 1
	} else {
		state = 0
	}
	bankcardRecord := g.Record{
		"id":          helper.GenId(),
		"uid":         uid,
		"username":    username,
		"pix_id":      pixId,
		"pix_account": pixAccount,
		"flag":        flag,
		"real_name":   realName,
		"created_at":  time.Now().Unix(),
		"bankcode":    bankCode,
		"bankname":    bankType.Bankname,
		"state":       state,
	}
	// 更新会员银行卡信息
	query, _, _ := dialect.Insert("tbl_member_bankcard").Rows(bankcardRecord).ToSQL()
	_, err = meta.MerchantDB.Exec(query)
	if err != nil {
		//_ = meta.MerchantDB.Rollback()
		return pushLog(fmt.Errorf("%s,[%s]", err.Error(), query), helper.DBErr)
	}

	//_ = tx.Commit()
	//key := "merchant:bankcard_exist"
	//_ = meta.MerchantRedis.SAdd(ctx, key, pixId).Err()
	return nil
}

func BankCardExistRedis(bankcardNo string) error {

	pipe := meta.MerchantRedis.Pipeline()
	defer pipe.Close()

	key1 := "merchant:bankcard_exist"
	key2 := "merchant:bankcard_blacklist"

	ex1Temp := pipe.SIsMember(ctx, key1, bankcardNo)

	ex2Temp := pipe.SIsMember(ctx, key2, bankcardNo)
	_, err := pipe.Exec(ctx)
	if err != nil {
		return pushLog(err, helper.RedisErr)
	}

	if ex1Temp.Val() {
		return errors.New(helper.BankCardExistErr)
	}

	if ex2Temp.Val() {
		return errors.New(helper.BankcardBan)
	}
	return nil
}

func BankcardList(uid string) (memberBankData, error) {

	var (
		data memberBankData
	)

	query, _, _ := dialect.From("tbl_member_bankcard").Select(colsBankcard...).Where(g.Ex{"uid": uid}).ToSQL()
	err := meta.MerchantDB.Select(&data.D, query)
	if err != nil {
		return data, pushLog(fmt.Errorf("%s,[%s]", err.Error(), query), helper.DBErr)
	}

	CfgSetPixCanWithdraw := myConfig.GetGameCfgInt(myConfig.CfgSetPixCanWithdraw)

	if CfgSetPixCanWithdraw == 1 {
		data.T = len(data.D)
		data.CardLimit = myConfig.GetGameCfgInt(myConfig.CfgCardBindLimit)
		return data, nil
	} else {
		CfgWithdrawPixType := myConfig.GetGameCfgInt(myConfig.CfgWithdrawPixType)
		validBankCard := make([]TblMemberBankcard, len(data.D))
		validIndex := 0
		for _, bankData := range data.D {
			userPixType := 0x01 << (bankData.Flag - 1)
			if (CfgWithdrawPixType)&(userPixType) == 0 {
				continue
			}

			validBankCard[validIndex] = bankData
			validIndex++
		}

		validBankCard = validBankCard[:validIndex]
		data.D = validBankCard
		data.T = len(data.D)
		data.CardLimit = myConfig.GetGameCfgInt(myConfig.CfgCardBindLimit)
		return data, nil
	}
}

func BankcardFindOne(id string, uid string) (TblMemberBankcard, error) {

	var (
		data TblMemberBankcard
	)

	query, _, _ := dialect.From("tbl_member_bankcard").Select(colsBankcard...).Where(g.Ex{"uid": uid, "pix_account": id}).Limit(1).ToSQL()
	err := meta.MerchantDB.Get(&data, query)
	if err != nil && err == sql.ErrNoRows {
		return data, pushLog(fmt.Errorf("%s,[%s]", err.Error(), query), helper.DBErr)
	}

	return data, nil
}

func BanktypeList() (bankTypeData, error) {

	var (
		data bankTypeData
	)

	query, _, _ := dialect.From("tbl_banktype").Select(colsBankType...).Where(g.Ex{"state": 1}).ToSQL()
	err := meta.SlaveDB.Select(&data.D, query)
	if err != nil {
		return data, pushLog(fmt.Errorf("%s,[%s]", err.Error(), query), helper.DBErr)
	}

	data.T = len(data.D)

	return data, nil
}

func bankNameByCode(bankcode string) (TblBanktype, error) {

	var (
		data TblBanktype
	)

	query, _, _ := dialect.From("tbl_banktype").Select(colsBankType...).Where(g.Ex{"bankcode": bankcode}).Limit(1).ToSQL()
	err := meta.MerchantDB.Get(&data, query)
	if err != nil && err != sql.ErrNoRows {
		return data, pushLog(fmt.Errorf("%s,[%s]", err.Error(), query), helper.DBErr)
	}

	if err == sql.ErrNoRows {
		return data, errors.New(helper.RecordNotExistErr)
	}

	return data, nil
}

func BankcardUpdateState(uid, pixId string, state int) error {

	myUserHelp.LoadUserToRedis(uid)

	// 开启事务
	tx, err := meta.MerchantDB.Begin()
	if err != nil {
		return pushLog(err, helper.DBErr)
	}
	defer func() {
		if err != nil {
			_ = tx.Rollback()
		} else {
			_ = tx.Commit()
		}
	}()

	var data []TblMemberBankcard
	que, _, _ := dialect.From("tbl_member_bankcard").Select(colsBankcard...).Where(g.Ex{"uid": uid}).ToSQL()
	err = meta.MerchantDB.Select(&data, que)
	if err != nil && err != sql.ErrNoRows {
		return pushLog(fmt.Errorf("%s,[%s]", err.Error(), que), helper.DBErr)
	}

	for _, i := range data {
		if i.PixId == pixId {
			// 找到匹配的银行卡，更新状态为传入的state
			i.State = state
		} else {
			// 其他银行卡状态设为0
			i.State = 0
		}

		// 更新银行卡状态到数据库
		record := g.Record{
			"state": i.State,
		}
		updateQuery, _, _ := dialect.Update("tbl_member_bankcard").Set(record).Where(g.Ex{"id": i.Id}).ToSQL()
		_, err = tx.Exec(updateQuery)
		if err != nil {
			return pushLog(fmt.Errorf("%s,[%s]", err.Error(), updateQuery), helper.DBErr)
		}
	}

	return nil
}
